/*
 * Created on 2006-7-28
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package com.powerunion.datacollection.report.excelreport.util;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * TODO :模板语法分析共用类，本类用来对定义的模板语法进行分析，其封装了所有于模板分析有关
 * 的函数，并将模板定义相关的关键字和语法分析部分集中在一起，便于管理和维护。
 * @author juny
 * @since 1.0
 */
public final class AnalyseTempletTool {
    /**
     * 判断传入的内容是否是一个模板元素
     * @param content 模板定义元素内容。（字符串描述）
     * @return true：当前传入内容是一个模板元素定义描述。 <br>
     * false当前传入内容不是一个模板元素定义描述。
     */
    public static boolean isTempletElement(String content){
        if(content.startsWith("$") && content.endsWith("}")){
            return true;
        }
        return false;
    }
    
    /**
     * 判断传入字符串是否是一个字段类型的模板元素定义。
     * @param templet 模板定义内容。
     * @return true 传入字符串是一个字段类模板元素定义。<br>
     * false 传入字符串不是一个字段类模板元素定义。
     * @since 1.0
     */
    public static boolean isFieldTemplet(String templet){
        if(templet.startsWith(KEY_ELEMENT_FIELD)){
            return true;
        }
        return false;
    }
    
    /**
     * 判断传入字符串是否是一个参数类型的模板元素定义。
     * @param templet 模板定义内容。
     * @return true 传入字符串是一个参数类模板元素定义。<br>
     * false 传入字符串不是一个参数类模板元素定义。
     * @since 1.0
     */
    public static boolean isArgumentTemplet(String templet){
        if(templet.startsWith(KEY_ELEMENT_ARGUMENT)){
            return true;
        }
        return false;
    }
    
    /**
     * 判断传入字符串是否是一个字符串字段类型的模板元素定义。
     * @param templet 模板定义内容。
     * @return true 传入字符串是一个字符串字段类型模板元素定义。<br>
     * false 传入字符串不是一个字符串字段类型模板元素定义。
     * @since 1.0
     */
    public static boolean isStringFieldTemplet(String templet){
        if(templet.startsWith(KEY_ELEMENT_STRING)){
            return true;
        }
        return false;
    }
    
    /**
     * 判断传入字符串是否是一个变量类型的模板元素定义。
     * @param templet 模板定义内容。
     * @return true 传入字符串是一个变量类模板元素定义。<br>
     * false 传入字符串不是一个变量类模板元素定义。
     * @since 1.0
     */
    public static boolean isVariableTemplet(String templet){
        if(templet.startsWith(KEY_ELEMENT_VARIABLE)){
            return true;
        }
        return false;
    }
    
    /**
     * 判断传入字符串是否是一个Band类型的模板元素定义。
     * @param templet 模板定义内容。
     * @return true 传入字符串是一个Band类模板元素定义。<br>
     * false 传入字符串不是一个Band类模板元素定义。
     * @since 1.0
     */
    public static boolean isBandTemplet(String templet){
        if(templet.startsWith(KEY_ELEMENT_BAND)){
            return true;
        }
        return false;
    }
    
    /**
     * 判断传入字符串是否是一个Group类型的模板元素定义。
     * @param templet 模板定义内容。
     * @return true 传入字符串是一个Group类模板元素定义。<br>
     * false 传入字符串不是一个Group类模板元素定义。
     * @since 1.0
     */
    public static boolean isGroupTemplet(String templet){
        if(templet.startsWith(KEY_ELEMENT_GROUP)){
            return true;
        }
        return false;
    }
    
    /**
     * 判断传入字符串是否含有head属性描述，如果有head属性描述在代表当前Band/Group Head
     * 部分的开始。该函数首先会检查传入内容是否是一个Band或Group的模板描述，不是则直接返回
     * false。
     * @param templet 传入模板定义内容。
     * @return true 当前传入模板是head。<br>
     * false 当前传入模板不是head.
     * @since 1.0
     */
    public static boolean isHead(String templet){
        if(isBandTemplet(templet) || isGroupTemplet(templet)){
            if(getPorperty(templet, PROPERTY_PROPE).equals(BAND_HEAD)){
                return true;
            }
        }
        return false;
    }
    
    /**
     * 判断传入字符串是否含有body属性描述，如果有body属性描述在代表当前Band/Group body
     * 部分的开始。该函数首先会检查传入内容是否是一个Band或Group的模板描述，不是则直接返回
     * false。
     * @param templet 传入模板定义内容。
     * @return true 当前传入模板是body。<br>
     * false 当前传入模板不是body.
     * @since 1.0
     */
    public static boolean isDetail(String templet){
        if(isBandTemplet(templet) || isGroupTemplet(templet)){
            if(getPorperty(templet, PROPERTY_PROPE).equals(BAND_BODY)){
                return true;
            }
        }
        return false;
    }
    
    /**
     * 判断传入字符串是否含有foot属性描述，如果有foot属性描述在代表当前Band/Group foot
     * 部分的开始。该函数首先会检查传入内容是否是一个Band或Group的模板描述，不是则直接返回
     * false。
     * @param templet 传入模板定义内容。
     * @return true 当前传入模板是foot。<br>
     * false 当前传入模板不是foot.
     * @since 1.0
     */
    public static boolean isBottom(String templet){
        if(isBandTemplet(templet) || isGroupTemplet(templet)){
            if(getPorperty(templet, PROPERTY_PROPE).equals(BAND_FOOT)){
                return true;
            }
        }
        return false;
    }
    
    /**
     * 判断传入字符串是否含有end属性描述，如果有end属性描述在代表当前Band/Group end
     * 部分的开始。该函数首先会检查传入内容是否是一个Band或Group的模板描述，不是则直接返回
     * false。
     * @param templet 传入模板定义内容。
     * @return true 当前传入模板是end。<br>
     * false 当前传入模板不是end.
     * @since 1.0
     */
    public static boolean isEnd(String templet){
        if(isBandTemplet(templet) || isGroupTemplet(templet)){
            if(getPorperty(templet, PROPERTY_PROPE).equals(BAND_END)){
                return true;
            }
        }
        return false;
    }
    
    /**
     * 从传入模板定义内容（templet）中取得指定属性的属性值。
     * @param templet 模板定义内容
     * @param propertyName 属性名称
     * @return 返回取得的属性值
     * @since 1.0
     */
    public static String getPorperty(String templet, byte propertyName){
        String strRet = null;
        //取出属性名及对应的值
        switch(propertyName){
        	case PROPERTY_NAME:
        	    strRet = getSubInfo(templet, REGEX_NAME);
        	    break;
        	case PROPERTY_PROPE:
        	    strRet = getSubInfo(templet, REGEX_PROPERTY);
        	    break;
        	case PROPERTY_DATASOURCE:
        	    strRet = getSubInfo(templet, REGEX_DATASOURCE);
        	    break;
        	default:
        	    ;
        }
        //取出属性值
        if(null != strRet){
            strRet = getSubInfo(strRet, REGEX_VALUE);
            if(!"".equals(strRet)){
	            //过滤掉一前一后的标识字符，取得属性对应的值.
	            strRet = strRet.substring(1, strRet.length() - 1).trim();
            }
        }else{
            strRet = "";
        }
        //返回属性对应的值
        return strRet;
    }
    
    /**
     * 利用正则表达式查找输入字符串中的一个子串，检索条件由searchRegex来指定。
     * @param content 传入需要查找的字符串。
     * @param searchRegex 传入查找条件，（一个正则表达式描述的字符串）。
     * @return 找到返回查找到的结果。
     */
    public static String getSubInfo(String content, String searchRegex){
        Matcher matcher = Pattern.compile(searchRegex).matcher(content);
        if(matcher.find()){
            //return matcher.toMatchResult().group();
            return content.substring(matcher.start(), matcher.end());
        }
        return "";
    }
    
    /**
     * 利用正则表达式查找输入字符串中的一个子串，检索条件由searchRegex来指定。
     * 其于getSubInfo(String, String)主要区别在于，后者只能返回一个结果。
     * @param content 传入需要查找的字符串。
     * @param searchRegex 传入查找条件，（一个正则表达式描述的字符串）。
     * @return 找到则返回查找到的结果，结果是一个用List保存的结果列表。
     */
    public static List getAllSubInfo(String content, String searchRegex){
        Matcher matcher = Pattern.compile(searchRegex).matcher(content);
        ArrayList list = new ArrayList();
        while(matcher.find()){
            list.add(content.substring(matcher.start(), matcher.end()));
        }
        return list;
    }
    
    /**
     * 取得模板变量声明的内容。
     * @param elementTemplet 传入模板定义内容。
     * @return 返回模板定义的实际内容，去掉描述符。
     */
    public static String getElementDeclare(String elementTemplet){
        if(elementTemplet.length()>=4 && isTempletElement(elementTemplet)){
            return elementTemplet.substring(3, elementTemplet.length()-1);
        }else{
            return elementTemplet;
        }
    }
    
    /**
     * 从模板元素定义中取出模板元素名称，如果有别名则取出别名做为元素名称返回
     * @param elementTemplet
     * @return
     */
    public static String getElementName(String elementTemplet){
        return getElementDeclare(elementTemplet);
    }
    
    /**
     * 从模板元素定义中取出模板元素名称，如果有别名则取出别名做为元素名称返回
     * @param elementTemplet
     * @return
     */
    public static String getElementName(StringBuffer elementTemplet){
        String declare = getElementDeclare(elementTemplet.toString());
        elementTemplet.setLength(0);
        elementTemplet.append(declare);
        
        String name = declare;
        return name;
    }
    
    /**
     * 判断一个模板变量是否定义了变量名称。每个模板变量都可以定义一个别名，
     * 以便在其他地方可以通过该名称引用该变得值。
     * @param content 传入模板定义内容。
     * @return true 当前模板存在变量名<br>
     * 
     */
    public static boolean haveVariableName(StringBuffer content){
        return content.charAt(0) == KEY_FIELD_NAME_DEFINE_BEGIN;
    }
    
    /**
     * 取得变量模板中定义的变量名称
     * @param content 模板定义内容
     * @return 如果模板定义了别名，则返回该别名，并删除原模板定义内容中定义别名部分。<br>
     * 否则返回null。
     */
    public static String getVariableName(StringBuffer content){
        int pos = content.lastIndexOf(AnalyseTempletTool.KEY_FIELD_NAME_DEFINE);
        String name = null;
        if(-1 != pos){
            name = content.substring(pos + 3, content.length()).trim();
        }
        
        //取得{}中的内容
        content.deleteCharAt(0);
        pos = content.lastIndexOf("}");
        if(-1 != pos){
            content.delete(pos, content.length());
        }
        return name;
    }
    
    public static String getProperties(StringBuffer comment){
    	String properties = getSubInfo(comment.toString(), REGEX_FIELD_PROPERTY_TEMPLET);
    	String normalComment = null;
    	if(HelpTools.notEmpty(properties)){
    		normalComment = HelpTools.replace(comment.toString(),
    				properties, "");
    		comment.delete(0, comment.length());
    		if(HelpTools.notEmpty(normalComment)){
    			comment.append(normalComment);
    		}
    		//去掉${...}中外面套用的语法描述符
            return properties.substring(2, properties.length()-1);
    	}
    	return properties;//修复但comment中不能取得${}字段定义信息时返回""
    }
    
    /* 报表支持的模板变量关键字定义 */
    private static final String KEY_ELEMENT_FIELD = "$F{";
    private static final String KEY_ELEMENT_ARGUMENT = "$P{";
    private static final String KEY_ELEMENT_VARIABLE = "$V{";
    private static final String KEY_ELEMENT_BAND = "$B{";
    private static final String KEY_ELEMENT_GROUP = "$G{";
    private static final String KEY_ELEMENT_STRING = "$S{";
    
    /* band 或者 group属性读取的表达式定义 */
    private static final String REGEX_NAME = "[nN]ame\\s*=.*?[;\\}]";
    private static final String REGEX_PROPERTY = "[pP]roperty\\s*=.*?[;\\}]";
    private static final String REGEX_DATASOURCE = "[dD]ata[sS]ource\\s*=.*?[;\\}]";
    private static final String REGEX_VALUE = "=.*[;\\}]";
    
    //模板变量－－该表达式描述一个模板变量定义语法
    public static final String REGEX_FIELD_TEMPLET = "\\$[fFpPvVbBgGSs]\\{.*?\\}";
    public static final byte PROPERTY_NAME = 1; //取模板中的name属性值
    public static final byte PROPERTY_PROPE = 2;//取模板中的property属性值
    public static final byte PROPERTY_DATASOURCE = 3; //取模板中的DataSource属性值 
    
    /* 字段表达式中数据源与字段名之间的分隔符定义 */
    public static final String DATASOURCE_FIELD_SEPARATOR_REGEX = "\\.";
    public static final String DATASOURCE_FIELD_SEPARATOR = ".";
    
    /* 带区域支持的属性定义 */
    public static final String BAND_HEAD = "head";
    public static final String BAND_BODY = "body";
    public static final String BAND_FOOT = "foot";
    public static final String BAND_END = "end";
    
    
    /* 计算域相关模板常量定义区 */
    public static final String REGEX_FIELD_BODY = "\\{.*\\}";
    public static final String KEY_FIELD_NAME_DEFINE = "as ";
    public static final char KEY_FIELD_NAME_DEFINE_BEGIN = '{';
    
    //定义模板元素附加属性
    public static final String REGEX_FIELD_PROPERTY_TEMPLET = "\\$\\{.*?\\}";//字段变量属性定义语法
    public static final String REGEX_FIELD_PROPERTY_NAME = "[nN]ame\\s*=\\s*'.*?'";
    public static final String REGEX_FIELD_PROPERTY_VALUE = "[vV]alue\\s*=\\s*'.*?'";
    public static final String REGEX_FIELD_PROPERTY_GET_VALUE = "'.*'";
    
    public static final String FIELD_PROPERTY_MERGECOLUM = "MergeColumn";
    public static final String FIELD_PROPERTY_IGNORESAMEVALUE = "IgnoreSameValue";
    public static final String FIELD_PROPERTY_MERGECOLUM_SPLIT = ",";
}
